package com.tiktok.config;

import com.alibaba.fastjson.JSON;
import com.tiktok.entity.SystemLog;
import com.tiktok.service.SystemLogService;
import com.tiktok.utils.UserContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 日志拦截器
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class LoggingInterceptor implements HandlerInterceptor {

    private final SystemLogService systemLogService;
    private static final String START_TIME_ATTR = "startTime";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 记录开始时间
        request.setAttribute(START_TIME_ATTR, System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            // 计算执行时间
            Long startTime = (Long) request.getAttribute(START_TIME_ATTR);
            long executionTime = startTime != null ? System.currentTimeMillis() - startTime : 0;

            // 创建系统日志
            SystemLog systemLog = new SystemLog();
            systemLog.setUserId(UserContext.getUserId());
            systemLog.setUsername(UserContext.getUsername());
            systemLog.setRequestUri(request.getRequestURI());
            systemLog.setRequestMethod(request.getMethod());
            systemLog.setRequestParams(getRequestParams(request));
            systemLog.setRequestBody(getRequestBody(request));
            systemLog.setResponseData(getResponseData(response));
            systemLog.setIpAddress(getClientIpAddress(request));
            systemLog.setUserAgent(request.getHeader("User-Agent"));
            systemLog.setExecutionTime(executionTime);
            systemLog.setStatus(String.valueOf(response.getStatus()));
            
            if (ex != null) {
                systemLog.setErrorMessage(ex.getMessage());
            }

            // 异步保存日志
            systemLogService.saveLogAsync(systemLog);

            // 控制台输出日志
            log.info("请求日志 - URI: {}, 方法: {}, 用户: {}, 耗时: {}ms, 状态: {}",
                    systemLog.getRequestUri(),
                    systemLog.getRequestMethod(),
                    systemLog.getUsername(),
                    systemLog.getExecutionTime(),
                    systemLog.getStatus());

        } catch (Exception e) {
            log.error("记录系统日志失败", e);
        }
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(HttpServletRequest request) {
        try {
            Map<String, String> params = new HashMap<>();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String paramName = parameterNames.nextElement();
                String paramValue = request.getParameter(paramName);
                // 过滤敏感信息
                if ("password".equalsIgnoreCase(paramName) || "token".equalsIgnoreCase(paramName)) {
                    paramValue = "***";
                }
                params.put(paramName, paramValue);
            }
            return params.isEmpty() ? null : JSON.toJSONString(params);
        } catch (Exception e) {
            log.warn("获取请求参数失败", e);
            return null;
        }
    }

    /**
     * 获取请求体
     */
    private String getRequestBody(HttpServletRequest request) {
        try {
            if (request instanceof ContentCachingRequestWrapper) {
                ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
                byte[] content = wrapper.getContentAsByteArray();
                if (content.length > 0) {
                    String body = new String(content, StandardCharsets.UTF_8);
                    // 过滤敏感信息
                    if (body.contains("password")) {
                        body = body.replaceAll("\"password\"\\s*:\\s*\"[^\"]*\"", "\"password\":\"***\"");
                    }
                    // 限制长度
                    return body.length() > 1000 ? body.substring(0, 1000) + "..." : body;
                }
            }
        } catch (Exception e) {
            log.warn("获取请求体失败", e);
        }
        return null;
    }

    /**
     * 获取响应数据
     */
    private String getResponseData(HttpServletResponse response) {
        try {
            if (response instanceof ContentCachingResponseWrapper) {
                ContentCachingResponseWrapper wrapper = (ContentCachingResponseWrapper) response;
                byte[] content = wrapper.getContentAsByteArray();
                if (content.length > 0) {
                    String responseData = new String(content, StandardCharsets.UTF_8);
                    // 过滤敏感信息
                    if (responseData.contains("token")) {
                        responseData = responseData.replaceAll("\"token\"\\s*:\\s*\"[^\"]*\"", "\"token\":\"***\"");
                    }
                    // 限制响应数据长度
                    return responseData.length() > 1000 ? responseData.substring(0, 1000) + "..." : responseData;
                }
            }
        } catch (Exception e) {
            log.warn("获取响应数据失败", e);
        }
        return null;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.hasText(xForwardedFor) && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (StringUtils.hasText(xRealIp) && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }
}